<template>
  <div class="frame-item" ref="wrapRef" :class="{'is-vertical': isVertical, 'editEnable': editEnable}" :style="`height: ${frameRect.height}px`">
    <template
      v-for="item in layoutConfigs" 
      :key="item.prop"
    >
      <div 
        :class="[`${item.align} ${item.prop} watermark`, {'text': item.prop !== 'logo'}]"
        :style="item.cssText"
        @click="logoClick(item)"
      >
        <p v-if="item.prop !== 'logo'" :contenteditEnable="editEnable" :spellcheck="false" @keyup="setLayout" @keydown.enter.prevent>{{ item.content }}</p>
        <img v-else :src="item.content" @load="logoOnload" />
      </div>
      <span class="separator" :class="[`${item.align}`]" v-if="item.separator" :style="item.separator.cssText"></span>
    </template>
  </div>
  <div class="edit-btns" v-if="editEnable">
    <el-button class="btn" @click="onMenuClick('cancel')" type="default" size="default">取消</el-button>
    <el-button class="btn" @click="onMenuClick('reset')" type="default" size="default">重置</el-button>
    <el-button class="btn" @click="onMenuClick('confirm')" type="danger" size="default">保存</el-button>
  </div>
  <el-drawer
    v-if="editEnable"
    class="drawer"
    :size="380"
    v-model="logoDrawerShow"
    title="选择LOGO"
    direction="ltr"
    :close-on-click-modal="false"
  >
    <LogoSelect v-if="logoDrawerShow" @success="logoSelectSuccess"/>
  </el-drawer>
</template>

<script setup>
  import {onMounted, ref, defineProps, computed, defineEmits, onBeforeUnmount, nextTick, reactive, watch } from 'vue'
  import LogoSelect from '../components/LogoSelect.vue'

  const props = defineProps({
    // 可自适应窗口缩放
    resizeEnable: {
      type: Boolean,
      default: false
    },
    // 可编辑
    editEnable: {
      type: Boolean,
      default: false
    },
    // 相框配置
    configs: {
      type: Array,
      default() {
        return []
      }
    }
  })

  watch(() => props.configs, () => {
    layoutConfigs.value = JSON.parse(JSON.stringify(props.configs))
    savedConfigs = JSON.parse(JSON.stringify(props.configs))
    init()
    setLayout()
  })

  const $emit = defineEmits(['menu-click'])

  const wrapRef = ref(null)
  const initialConfigs = JSON.parse(window.localStorage.getItem('frameConfigs')) || [] // 重置的configs
  const layoutConfigs = ref(JSON.parse(JSON.stringify(props.configs))) // 布局configs
  let savedConfigs = JSON.parse(JSON.stringify(props.configs)) // 每次保存的config缓存
  const logoDrawerShow = ref(false)
  let logo = null

  // 相框信息
  const frameRect = reactive({
    width: 0,
    height: 0,
  })

  // logo选择成功
  const logoSelectSuccess = (e) => {
    logoDrawerShow.value = false
    const logoItem = layoutConfigs.value.find(item => item.prop === 'logo')
    logoItem.content = e.url
  }

  const logoOnload = (e) => {
    logo = e.target
    setLayout()
  }



  // 单列水平垂直居中布局
  const isVertical = computed(() => {
    let aligns = props.configs.map(item => item.align)
    if (aligns.includes('center-top') || aligns.includes('center-bottom')) {
      return true
    }
    return false
  })

  // 宽高比 单列水平垂直居中宽高比为9，多列水平排版宽高比为11
  const proportion = computed(() => {
    if (isVertical.value) {
      return 9
    }
    return 11
  })

  // 获取水印所在位置的内容配置项
  const getAlignItem = (alignValue, frameConfigs) => {
    return frameConfigs.find(item => item.align === alignValue)
  }

  const setLayout = () => {
    const configs = layoutConfigs.value
    const aligns = configs.map(item => item.align)
    const padding = frameRect.height * 0.25 // 水平内间距
    const lineHeight = frameRect.height * 0.55 // 分割线高度
    let logoHeight = logo.naturalWidth / logo.naturalHeight < 2 ? lineHeight * 0.9 : frameRect.height * 0.3
    if (isVertical.value) {
      logoHeight = logo.naturalWidth / logo.naturalHeight < 2 ? frameRect.height * 0.3 : frameRect.height * 0.23
    }
    let logoWidth = logoHeight * (logo.naturalWidth / logo.naturalHeight)
    const lineXMargin = frameRect.width * 0.02 // 分割线水平间距
    const marginBottom = aligns.length > 2 ? frameRect.height * 0.08 : frameRect.height * 0.12 // 内容底部间距

    configs.forEach((item) => {
      if (item.prop !== 'logo') {
        let {fontWeight, fontColor, fontRatio} = item.style
        item.cssText = `
          font-size: ${frameRect.height * fontRatio}px;
          font-weight: ${fontWeight};
          color: ${fontColor};
          min-width: ${0}px;
        `
        item.height = frameRect.height * fontRatio
      } else {
        item.cssText = `width: ${logoWidth}px;height: ${logoHeight}px;`
        item.height = logoHeight
        // logo分割线
        if (aligns.includes('left-middle') || aligns.includes('offset-right-middle')) {
          item.separator = {
            cssText: ''
          }
        }
      }
    })

    // 记录每列文字总高度 (用于处理计算垂直居中)
    const unfound = {height: 0}
    const leftTopItem = getAlignItem('left-top', configs) || unfound
    const leftBottomItem = getAlignItem('left-bottom', configs) || unfound
    const rightTopItem = getAlignItem('right-top', configs) || unfound
    const rightBottomItem = getAlignItem('right-bottom', configs) || unfound
    const offsetLeftTopItem = getAlignItem('offset-left-top', configs) || unfound
    const offseLeftBottomItem = getAlignItem('offset-left-bottom', configs) || unfound
    const centerTopItem = getAlignItem('center-top', configs) || unfound
    const centerMiddleItem = getAlignItem('center-middle', configs) || unfound
    const centerBottomItem = getAlignItem('center-bottom', configs) || unfound
    const colRect = {
      leftContentHeight: leftTopItem.height + marginBottom + leftBottomItem.height,
      rightContentHeight: rightTopItem.height + marginBottom + rightBottomItem.height,
      offsetLeftContentHeight: offsetLeftTopItem.height + marginBottom + offseLeftBottomItem.height,
      centerMiddleContentHeight: centerTopItem.height + marginBottom + (centerMiddleItem.height ? (centerMiddleItem.height + marginBottom) : 0) + centerBottomItem.height
    }

    nextTick(() => {
      let rightTextWidth = 0
      const rightTopItem = configs.find(item => item.align === 'right-top')
      const rightBottomItem = configs.find(item => item.align === 'right-bottom')
      if (rightTopItem && rightBottomItem) {
        rightTextWidth = Math.max(wrapRef.value.querySelector('.right-top').clientWidth, wrapRef.value.querySelector('.right-bottom').clientWidth)
      }
      configs.forEach(item => {
        switch(item.align) {
          case 'left-top':
            item.cssText = `
              ${item.cssText}
              left: ${padding}px; 
              top: ${(frameRect.height - colRect.leftContentHeight) / 2}px; 
            `
            break
          case 'left-bottom':
            item.cssText = `
              ${item.cssText}
              left: ${padding}px; 
              top: ${leftTopItem.height + marginBottom + (frameRect.height - colRect.leftContentHeight) / 2}px; 
            `
            break
          case 'right-top': 
            item.cssText = `${item.cssText} right: ${padding}px; top: ${(frameRect.height - colRect.rightContentHeight) / 2}px;`
            if (rightTextWidth) {
              item.cssText += `min-width: ${rightTextWidth}px;`
            }
            break
          case 'right-bottom': 
            item.cssText = `
              ${item.cssText} 
              right: ${padding}px; 
              top: ${rightTopItem.height + marginBottom + (frameRect.height - colRect.rightContentHeight) / 2}px; 
            `
            if (rightTextWidth) {
              item.cssText += `min-width: ${rightTextWidth}px;`
            }
            break
          case 'offset-right-middle':
            item.cssText = `${item.cssText} right: ${rightTextWidth + 2 * lineXMargin + padding}px;`
            item.separator.cssText = `height: ${lineHeight}px; right: ${rightTextWidth + lineXMargin + padding}px;`
            break
          case 'left-middle':
            item.cssText = `${item.cssText} left: ${padding}px;`
            item.separator.cssText = `height: ${lineHeight}px; left: ${logoWidth + padding + lineXMargin}px;`
            break
          case 'offset-left-top':
            item.cssText = `${item.cssText} left: ${logoWidth + 2 * lineXMargin + padding}px; 
              top: ${(frameRect.height - colRect.offsetLeftContentHeight) / 2}px; 
            `
            break
          case 'offset-left-bottom':
            item.cssText = `${item.cssText} left: ${logoWidth + 2 * lineXMargin + padding}px; 
              top: ${offsetLeftTopItem.height + marginBottom + (frameRect.height - colRect.offsetLeftContentHeight) / 2}px;
            `
            break
          case 'center-top':
            item.cssText = `${item.cssText} 
              top: ${(frameRect.height - colRect.centerMiddleContentHeight) / 2}px;
            `
            break
          case 'center-middle':
            item.cssText = `${item.cssText} 
              top: ${logoHeight + marginBottom + (frameRect.height - colRect.centerMiddleContentHeight) / 2}px;
            `
            break
          case 'center-bottom':
            item.cssText = `${item.cssText} 
              top: ${logoHeight + marginBottom + (centerMiddleItem.height ? (centerMiddleItem.height + marginBottom) : 0) + (frameRect.height - colRect.centerMiddleContentHeight) / 2}px;
            `
            break
          default:
            return null
        }
      })
    })
  }


  const init = () => {
    const wrap = wrapRef.value
    frameRect.width = wrap.clientWidth
    frameRect.height = wrap.clientWidth / proportion.value
  }

  const resizeObserver = props.resizeEnable ? new ResizeObserver(() => {
    if (!logo) {
      return
    }
    init()
    setLayout()
  }) : null

  onMounted(() => {
    document.addEventListener('click', inputBlur)
    nextTick(() => {
      init()
      // 在DrawView组件里自适应窗口宽度
      if (resizeObserver) {
        resizeObserver.observe(document.body)
      }
    })
  })

  onBeforeUnmount(() => {
    document.removeEventListener('click', inputBlur)
    savedConfigs = null
    logo = null
    if (resizeObserver) {
      resizeObserver.unobserve(document.body)
    }
  })


  const update = mode => {
    const configs = mode === 'reset' ? JSON.parse(JSON.stringify(initialConfigs)) : JSON.parse(JSON.stringify(savedConfigs))
    const watermarks = wrapRef.value.querySelectorAll('.watermark')
    const configLogoItem = configs.find(item => item.prop === 'logo')
    const layoutLogoItem = layoutConfigs.value.find(item => item.prop === 'logo')
    if (mode === 'reset' || mode === 'cancel') {
      Array.prototype.forEach.call(watermarks, el => {
        const textEl = el.querySelector('p')
        if (textEl) {
          const findItem = configs.find(item => el.className.split(' ').includes(item.prop))
          if (findItem) {
            textEl.innerText = findItem.content.trim()
          }
        }
      })
      if (layoutLogoItem.content !== configLogoItem.content) {
        layoutLogoItem.content = configLogoItem.content
      } else {
        setLayout()
      }
    }
    if (mode === 'confirm') {
      Array.prototype.forEach.call(watermarks, el => {
        const textEl = el.querySelector('p')
        if (textEl) {
          configs.find(item => el.className.split(' ').includes(item.prop)).content = textEl.innerText.trim()
        }
      })
      if (configLogoItem.content !== layoutLogoItem.content) {
        configLogoItem.content = layoutLogoItem.content
      }
      savedConfigs = configs
    }
  }

  const onMenuClick = name => {
    // 重置
    if (name === 'reset') {
      update('reset')
    }
    // 取消
    if (name === 'cancel') {
      update('cancel')
    }
    // 确认
    if (name === 'confirm') {
      update('confirm')
    }
    $emit('menu-click', {
      name,
      configs: name === 'confirm' ? savedConfigs : []
    })
  }

  const inputBlur = () => {
    const configs = savedConfigs
    const textEls = wrapRef.value.querySelectorAll('.text')
    Array.prototype.forEach.call(textEls, el => {
      const p = el.querySelector('p')
      // 当清空输入时候，自动补充上次保存的内容
      if (p.innerText.trim() === '') {
        p.innerText = configs.find(item => el.className.split(' ').includes(item.prop)).content
        setLayout()
      }
    })
  }

  const logoClick = item => {
    if (item.prop === 'logo' && props.editEnable) {
      logoDrawerShow.value = true
    }
  }
  
</script>

<style lang="less" scoped>
  .frame-item {
    background-color: #fff;
    font-family: Arial, Helvetica, sans-serif;
    overflow: hidden;
    position: relative;
    text-align: left;
    line-height: 1;
    &.editEnable {
      :deep(.text),:deep(.logo) {
        border: 1px dashed #51a5ff;
        caret-color: #000000;
        outline: none;
        p {
          -webkit-user-select: auto; /* Safari */
          user-select: auto; /* Standard syntax */
          -webkit-user-modify: read-write-plaintext-only;
          user-modify: read-write-plaintext-only;
        }
      }
      :deep(.logo) {
        cursor: pointer;
      }
    }
    &.is-vertical {
      :deep(.text),:deep(.logo) {
        left: 50%;
        transform: translateX(-50%);
      }
    }
    :deep(.text),:deep(.logo) {
      position: absolute;
      word-break: keep-all;
      white-space: nowrap;
      box-sizing: content-box;
      p {
        outline: none;
      }
    }
    :deep(.logo) {
      img {
        display: block;
        height: 100%;
      }
      // 遮盖图片: 禁止拖拽图片到电脑桌面
      &:after {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        background-color: rgba(0,0,0,0);
      }
      &.left-middle, &.offset-right-middle {
        top: 50%; 
        transform: translateY(-50%);
      }
    }
    :deep(.separator) {
      position: absolute;
      width: 1px;
      background-color: #c6c6c6;
      &.left-middle, &.offset-right-middle {
        top: 50%; 
        transform: translateY(-50%);
      }
    }
  }
  .edit-btns {
    margin-top: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 15px;
    background-color: #222;
    .btn {
      
    }
  }
</style>
